package testing;

import hypeerweb.*;
import java.util.Iterator;
import org.junit.Test;

import proxyCommand.GlobalObjectId;
import states.*;
import visitor.*;
import static org.junit.Assert.*;

public class KendraTests {
	
	@Test
	public void testConditional() {
		//UpPointingNodeState.shrinkRange
		HyPeerWeb hp = HyPeerWeb.getSingleton(new GlobalObjectId());
		createHyPeerWebWithSize(hp, 10);
		
		Range r = new Range(hp.getNode(9), hp.getNode(2));
		assertTrue((new UpPointingNodeState()).shrinkRange(r) instanceof TerminalNodeState);
		r.toString();
		
		r = new Range(hp.getNode(7), hp.getNode(3));
		assertTrue((new UpPointingNodeState()).shrinkRange(r) instanceof DownPointingNodeState);
		r.toString();
		
		r = new Range(hp.getNode(7), hp.getNode(7));
		assertTrue((new UpPointingNodeState()).shrinkRange(r) instanceof StandardNodeState);
		r.toString();
		
		r = new Range(hp.getNode(9), hp.getNode(3));
		assertTrue((new UpPointingNodeState()).shrinkRange(r) instanceof StandardNodeState);
		r.toString();
		(new UpPointingNodeState()).toString();
	}
	
	@Test
	public void testLoop() {
		//Range.getNodeRange
		HyPeerWeb hp = HyPeerWeb.getSingleton(new GlobalObjectId());
		createHyPeerWebWithSize(hp, 16);
		
		Range r = Range.getNodeRange(Node.NULL_NODE);			//Two passes through
		assertTrue(r.getLowerBound().getWebId().getValue() == 15);
		assertTrue(r.getUpperBound().getWebId().getValue() == 0);
		
		r = Range.getNodeRange(hp.getNode(15));			//Two passes through
		assertTrue(r.getLowerBound().getWebId().getValue() == 15);
		assertTrue(r.getUpperBound().getWebId().getValue() == 0);
		
		createHyPeerWebWithSize(hp, 31);
		r = Range.getNodeRange(hp.getNode(7));			//Three passes through
		System.out.println(r.getLowerBound());
		assertTrue(r.getLowerBound().getWebId().getValue() == 30);
		assertTrue(r.getUpperBound().getWebId().getValue() == 15);
		
		createHyPeerWebWithSize(hp, 10);
		r = Range.getNodeRange(hp.getNode(7));			//Many passes through
		assertTrue(r.getLowerBound().getWebId().getValue() == 9);
		assertTrue(r.getUpperBound().getWebId().getValue() == 2);
	}
	
	@Test
	public void testDataFlow() {
		//UpPointingNodeState.shrinkRange
		HyPeerWeb hp = HyPeerWeb.getSingleton(new GlobalObjectId());
		createHyPeerWebWithSize(hp, 10);
		
		Range r = new Range(hp.getNode(9), hp.getNode(2));
		(new UpPointingNodeState()).shrinkRange(r);
		assertTrue(r.getLowerBound().getWebId().getValue() == 9);
		assertTrue(r.getUpperBound().getWebId().getValue() == 2);
		r.toString();
		
		r = new Range(hp.getNode(7), hp.getNode(3));
		(new UpPointingNodeState()).shrinkRange(r);
		assertTrue(r.getLowerBound().getWebId().getValue() == 9);
		assertTrue(r.getUpperBound().getWebId().getValue() == 3);
		r.toString();
		
		r = new Range(hp.getNode(7), hp.getNode(7));
		(new UpPointingNodeState()).shrinkRange(r);
		assertTrue(r.getLowerBound().getWebId().getValue() == 7);
		assertTrue(r.getUpperBound().getWebId().getValue() == 7);
		r.toString();
		
		r = new Range(hp.getNode(9), hp.getNode(3));
		(new UpPointingNodeState()).shrinkRange(r);
		assertTrue(r.getLowerBound().getWebId().getValue() == 9);
		assertTrue(r.getUpperBound().getWebId().getValue() == 3);
		r.toString();
	}
	
	@Test
	public void testBoundaries() {
		//getNode
		HyPeerWeb hp = HyPeerWeb.getSingleton(new GlobalObjectId());
		createHyPeerWebWithSize(hp, 10);
		assertTrue(hp.getNode(-10) == null);
		assertTrue(hp.getNode(-1) == null);
		assertTrue(hp.getNode(0) != null);
		assertTrue(hp.getNode(5) != null);
		assertTrue(hp.getNode(9) != null);
		assertTrue(hp.getNode(10) == null);
		assertTrue(hp.getNode(20) == null);
	}
	
	
	//-----------------------------------------------------------------------------------
	//-----------------------------------------------------------------------------------
	static private void createHyPeerWebWithSize(HyPeerWeb hypeerweb, int numberOfNodes) {
		hypeerweb.clear();
		hypeerweb.addToHyPeerWeb(0, -1);

		for (int i = 1; i < numberOfNodes; i++) {
			hypeerweb.addToHyPeerWeb(0, 0);
		}
	}
	
	public boolean allNodesHaveMessage(HyPeerWeb hp) {
		Iterator<Node> nodes = hp.iterator();
		while(nodes.hasNext()) {
			Node n = nodes.next();
			if(!n.getContents().get(DepositBroadcastVisitor.DEPOSIT_KEY).equals("Hello!")) {
				return false;
			}
		}
		return true;
	}
	
	public boolean broadcast(int startNode, int size) {
		HyPeerWeb hp = HyPeerWeb.getSingleton(new GlobalObjectId());
		createHyPeerWebWithSize(hp, size);
		DepositBroadcastVisitor db = new DepositBroadcastVisitor();
		Parameters p = BroadcastVisitor.createInitialParameters();
		p.set(DepositBroadcastVisitor.DEPOSIT_KEY, "Hello!");
		
		Node n = hp.getNode(startNode);
		db.visit(n, p);
		
		return allNodesHaveMessage(hp);
	}
	
	public boolean noNodesHaveMessage(HyPeerWeb hp) {
		Iterator<Node> nodes = hp.iterator();
		while(nodes.hasNext()) {
			Node n = nodes.next();
			if(n.getContents().containsKey(DepositBroadcastVisitor.DEPOSIT_KEY)) {
				return false;
			}
		}
		return true;
	}
	
	public boolean broadcastBadNode(int startNode, int size) {
		HyPeerWeb hp = HyPeerWeb.getSingleton(new GlobalObjectId());
		createHyPeerWebWithSize(hp, size);
		DepositBroadcastVisitor db = new DepositBroadcastVisitor();
		Parameters p = BroadcastVisitor.createInitialParameters();
		p.set(DepositBroadcastVisitor.DEPOSIT_KEY, "Hello!");
		
		Node n = new Node(startNode);
		db.visit(n, p);
		
		return noNodesHaveMessage(hp);
	}
}
